package com.qipay.admin.order.controller;

import com.qipay.admin.BaseController;
import com.qipay.admin.order.service.OrderLogicService;
import com.qipay.admin.order.vo.OrderVo;
import com.qipay.admin.tags.PageModel;
import com.qipay.admin.withdraw.service.GoogleAuthenticator;
import com.qipay.baas.model.*;
import com.qipay.cp.CpService;
import com.qipay.excel.service.ExcelUtils;
import com.qipay.ips.service.IpsService;
import com.qipay.mapper.SpUserMapper;
import com.qipay.notify.NotifyLogService;
import com.qipay.order.config.OrderQueryEnum;
import com.qipay.order.config.OrderStateEnum;
import com.qipay.order.service.OrderService;
import com.qipay.order.vo.OrderSumVo;
import com.qipay.security.UserDetailsServiceImpl;
import com.qipay.user.entity.UserLevel;
import com.qipay.utils.CommonUtil;
import com.qipay.utils.GuavaCacheUtils;
import com.qipay.utils.Result;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Controller
@RequestMapping("/order")
public class OrderController extends BaseController {
    @Autowired
    GuavaCacheUtils guavaCacheUtils;
    @Autowired
    OrderLogicService orderLogicService;
    @Autowired
    ExcelUtils excelUtils;
    @Autowired
    OrderService orderService;
    @Autowired
    NotifyLogService notifyLogService;
    @Autowired
    CpService cpService;
    @Autowired
    SpUserMapper spUserMapper;

    @Autowired
    IpsService ipsService;

    private final static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

    @RequestMapping(value = {"/", ""}, method = RequestMethod.GET)
    public ModelAndView list(
            @AuthenticationPrincipal UserDetailsServiceImpl.LoginUserDetails loginUser,Sp sp,HttpServletRequest  request,
            @RequestParam(value = "cpId", required = false, defaultValue = "") String cpId,
            @RequestParam(value = "channel", required = false, defaultValue = "0") Integer channel,
            @RequestParam(value = "state", required = false, defaultValue = "") Byte state,
            @RequestParam(value = "tradeNo", required = false, defaultValue = "") String tradeNo,
            @RequestParam(value = "outTradeNo", required = false, defaultValue = "") String outTradeNo,
            @RequestParam(value = "body", required = false, defaultValue = "") String body,
            @RequestParam(value = "spTradeNo", required = false, defaultValue = "") String spTradeNo,
            @RequestParam(value = "from", required = false, defaultValue = "") String from,
            @RequestParam(value = "to", required = false, defaultValue = "") String to,
            @RequestParam(value = "spId", required = false, defaultValue = "0") Long spId,
            @RequestParam(value = "p", required = false, defaultValue = "1") int p,
            @RequestParam(value = "pz", required = false, defaultValue = "30") int pz
    ) throws UnsupportedEncodingException {
        String spUserName = null;
        if(CommonUtil.isInteger(loginUser.getUsername())&&loginUser.getLevel().getCode()>UserLevel.AGENT.getCode()){
            SpUser spUser = spUserMapper.selectByPrimaryKey(Integer.valueOf(loginUser.getUsername()));
            spUserName=spUser.getName();
        }
        // init
        ModelAndView view = createModelAndView("order-lst");
        UserLevel level = loginUser.getLevel();
        List<List<String>> lst = new ArrayList<>();
        long total = 0;
        long amountCount = 0;
        long feeCount = 0;
        sp=new Sp();
        // param.init
        if (StringUtils.isBlank(to) || StringUtils.isBlank(from)) {
            Calendar calendar = Calendar.getInstance();
            from = format.format(calendar.getTime())+" 00:00";
            calendar.add(Calendar.DAY_OF_YEAR, 1);
            to = format.format(calendar.getTime())+" 00:00";
        }
        //Map<String, Object> map = handlerParams(level, loginUser.getUsername(), cpId , channel, state, tradeNo, outTradeNo, spTradeNo, from, to,spId);
        p = p < 1 ? 1 : p;
        pz = pz <= 0 ? 10 : pz;
        String offset = String.valueOf((p - 1) * pz);
        String rows = String.valueOf(pz);

        String querySql = orderLogicService.general(level, loginUser.getUsername(), cpId , channel, state, tradeNo, outTradeNo, spTradeNo, from, to,spId,body,spUserName);
        // query
        OrderSumVo orderSum = orderLogicService.sumBy(querySql);
        total = orderSum.getTotal();
        if (total > 0) {
            lst = orderLogicService.listBy(querySql,offset,rows);
        }
        amountCount = orderSum.getAmountCount();
        feeCount = orderSum.getFeeCount();
        // fill
        view.addObject("total", total);
        view.addObject("lst", lst);
        view.addObject("level", level);
        view.addObject("channelTypes", guavaCacheUtils.getChanelTypes());

        view.addObject("states", mapState());
        view.addObject("amountCount", amountCount);
        view.addObject("feeCount", feeCount);
        view.addObject("advanceAmount", orderSum.getAdvanceAmount());
        view.addObject("sp",sp);
        PageModel pageModel = new PageModel();
        pageModel.setPage(p);
        pageModel.setPageSize(pz);

        // url.init
        String url = "?";
        Map<String, String> params = new HashMap<>();

        if (StringUtils.isNotBlank(cpId)) {
            url += String.format("&cpId=%s", URLEncoder.encode(cpId, "utf8"));
            params.put("cpId", cpId);
        }
        if (spId!=null&&0!=spId) {
            url += String.format("&spId=%s", spId);
            params.put("spId", spId.toString());
        }

        if (null != channel && channel != 0) {
            url += String.format("&channel=%s", channel);
            params.put("channel", channel.toString());
        }
        if (null != state && state != 0) {
            url += String.format("&state=%s", state);
            params.put("state", state.toString());
        }
        if (StringUtils.isNotBlank(tradeNo)) {
            url += String.format("&tradeNo=%s", URLEncoder.encode(tradeNo, "utf8"));
            params.put("tradeNo", tradeNo);
        }
        if (StringUtils.isNotBlank(outTradeNo)) {
            url += String.format("&outTradeNo=%s", URLEncoder.encode(outTradeNo, "utf8"));
            params.put("outTradeNo", outTradeNo);
        }
        if (StringUtils.isNotBlank(body)) {
            url += String.format("&body=%s", URLEncoder.encode(body, "utf8"));
            params.put("body", body);
        }
        if (StringUtils.isNotBlank(spTradeNo)) {
            url += String.format("&spTradeNo=%s", URLEncoder.encode(spTradeNo, "utf8"));
            params.put("spTradeNo", spTradeNo);
        }
        if (StringUtils.isNotBlank(from)) {
            url += String.format("&from=%s", URLEncoder.encode(from.toString(), "utf8"));
            params.put("from", from.toString());
        }
        if (StringUtils.isNotBlank(to)) {
            url += String.format("&to=%s", URLEncoder.encode(to.toString(), "utf8"));
            params.put("to", to.toString());
        }
        if (!"?".equalsIgnoreCase(url)) {
            pageModel.setUrl(url);
        }
        view.addObject("params", params);

        pageModel.setTotal(total);
        view.addObject("page", pageModel);
        return view;
    }

    @RequestMapping(value = "/export", method = RequestMethod.GET)
    public void export(
            @AuthenticationPrincipal UserDetailsServiceImpl.LoginUserDetails loginUser,
            @RequestParam(value = "cpId", required = false, defaultValue = "") String cpId,
            @RequestParam(value = "channel", required = false, defaultValue = "0") Integer channel,
            @RequestParam(value = "state", required = false, defaultValue = "0") Byte state,
            @RequestParam(value = "tradeNo", required = false, defaultValue = "") String tradeNo,
            @RequestParam(value = "outTradeNo", required = false, defaultValue = "") String outTradeNo,
            @RequestParam(value = "body", required = false, defaultValue = "") String body,
            @RequestParam(value = "spTradeNo", required = false, defaultValue = "") String spTradeNo,
            @RequestParam(value = "from", required = false, defaultValue = "") String from,
            @RequestParam(value = "to", required = false, defaultValue = "") String to,
            @RequestParam(value = "spId", required = false, defaultValue = "0") Long spId,
            HttpServletResponse resp
    ) throws IOException, ParseException {
        // param.init
        //Map<String, Object> map = handlerParams(loginUser.getLevel(), loginUser.getUsername(), cpId, channel, state, tradeNo, outTradeNo, spTradeNo, from, to);
        //String querysql = orderLogicService.general(map);
        String querySql = orderLogicService.general(loginUser.getLevel(), loginUser.getUsername(), cpId , channel, state, tradeNo, outTradeNo, spTradeNo, from, to,spId,body);

        excelUtils.download(resp, orderLogicService.exportBy(querySql,0,Integer.MAX_VALUE));
    }

    private Map<String, Object> handlerParams(Object... params) {
        // init
        Map<String, Object> map = new HashMap<>();

        // init.params
        UserLevel level = (UserLevel) params[0];
        String username = (String) params[1];
        String cpId = (String) params[2];
        Integer channel = (Integer) params[3];
        Byte state = (Byte) params[4];
        String tradeNo = (String) params[5];
        String outTradeNo = (String) params[6];
        String spTradeNo = (String) params[7];
        String from = (String) params[8];
        String to = (String) params[9];
        Long spId = null;
        if (params.length>10){
            spId = (Long) params[10];
        }
        // level.params
        if (level == UserLevel.AGENT) {
            map.put(OrderQueryEnum.AGENT_ID.getParam(), username);
        } else if (level == UserLevel.CP) {
            map.put(OrderQueryEnum.CP_ID.getParam(), username);
        }
        // init.params.check
        if (StringUtils.isNotBlank(cpId))
            map.put(OrderQueryEnum.CP_ID.getParam(), cpId);
        if (null != channel && channel != 0)
            map.put(OrderQueryEnum.CHANNEL.getParam(), channel);
        if (null != state && state != 0)
            map.put(OrderQueryEnum.STATE.getParam(), state);
        if (StringUtils.isNotBlank(tradeNo))
            map.put(OrderQueryEnum.TRADE_NO.getParam(), tradeNo);
        if (StringUtils.isNotBlank(spTradeNo))
            map.put(OrderQueryEnum.SP_TRADE_NO.getParam(), spTradeNo);
        if (StringUtils.isNotBlank(outTradeNo))
            map.put(OrderQueryEnum.OUT_TRADE_NO.getParam(), outTradeNo);
        if (StringUtils.isNotBlank(from))
            map.put(OrderQueryEnum.FROM.getParam(), from);
        if (StringUtils.isNotBlank(to))
            map.put(OrderQueryEnum.TO.getParam(), to);
        if (StringUtils.isBlank(to) && StringUtils.isBlank(from)) {
            Calendar calendar = Calendar.getInstance();
            from = format.format(calendar.getTime())+" 00:00";
            map.put(OrderQueryEnum.FROM.getParam(), from);
            calendar.add(Calendar.DAY_OF_YEAR, 1);
            to = format.format(calendar.getTime())+" 00:00";
            map.put(OrderQueryEnum.TO.getParam(), to);
        }
        if (null != spId &&  spId!=0)
            map.put(OrderQueryEnum.SP_ID.getParam(), spId);
        return map;
    }


    @ResponseBody
    @RequestMapping(value = "/{orderId:\\d+}/{verifyCode:\\d+}/setSuccess/", method = RequestMethod.PUT)
    public Result setSuccess(
            @AuthenticationPrincipal UserDetailsServiceImpl.LoginUserDetails loginUser,
            @PathVariable(name = "orderId", required = true) Long orderId,
            @PathVariable(name = "verifyCode", required = true) Long verifyCode) {
        Result result = new Result<>();
        List<WhiteIps> whiteIpsList = ipsService.query(loginUser);
        if (whiteIpsList.size()>0){
            String secret=whiteIpsList.get(0).getIpAddress();

            long code1 = Long.valueOf(verifyCode);
            long t = System.currentTimeMillis();
            GoogleAuthenticator ga = new GoogleAuthenticator();
            ga.setWindowSize(1);
            boolean r = ga.check_code(secret, code1, t);
            if (!r){//验证不成功
                result.setCode(400);
                result.setMsg("验证码错误");
                return result;
            }
        }
        try {
            orderService.setOrderSuccess(orderId,null);
        } catch (Exception e) {
            result.setCode(-1);
            result.setMsg(e.getMessage());
        }
        result.setCode(200);
        return result;
    }

    @ResponseBody
    @RequestMapping(value = "/{tradeNo}/notify", method = RequestMethod.PUT)
    public Result notify(
            @AuthenticationPrincipal UserDetailsServiceImpl.LoginUserDetails loginUser,
            @PathVariable(name = "tradeNo", required = true) String tradeNo) {

        // init
        Result result = new Result<>();
        // logic
        try {
            Order order = orderService.getByTradeNo(tradeNo);
            Cp cp = cpService.getOneById(order.getCpId());
            notifyLogService.setOrderSuccess(order, cp);
            result.setCode(200);
        } catch (Exception e) {
            result.setCode(-1);
            result.setMsg(e.getMessage());
        }
        return result;
    }

    @RequestMapping(value = "/{orderId:\\d+}", method = RequestMethod.GET)
    public ModelAndView get(@PathVariable(name = "orderId", required = true) Long orderId) {

        // init
        ModelAndView view = createModelAndView("order-detail");
        OrderVo order = orderLogicService.get(orderId);

        // fill
        view.addObject("detail", order);
        return view;
    }

    @ResponseBody
    @RequestMapping(value = "/{orderId:\\d+}/freeze", method = RequestMethod.PUT)
    public Result freeze(
            @AuthenticationPrincipal UserDetailsServiceImpl.LoginUserDetails loginUser,
            @PathVariable(name = "orderId", required = true) Long orderId) {

        // init
        Result result = new Result<>();

        // logic
        try {
            orderLogicService.freeze(loginUser, orderId);
            result.setCode(200);
        } catch (Exception e) {
            result.setCode(-1);
            result.setMsg(e.getMessage());
        }

        return result;
    }

    @ResponseBody
    @RequestMapping(value = "/{orderId:\\d+}/unfreeze", method = RequestMethod.PUT)
    public Result unfreeze(
            @AuthenticationPrincipal UserDetailsServiceImpl.LoginUserDetails loginUser,
            @PathVariable(name = "orderId", required = true) Long orderId) {
        // init
        Result result = new Result<>();
        // logic
        try {
            orderLogicService.unfreeze(loginUser, orderId);
            result.setCode(200);
        } catch (Exception e) {
            result.setCode(-1);
            result.setMsg(e.getMessage());
        }

        return result;
    }

    private Map<Short, String> mapState() {

        // init
        Map<Short, String> map = new TreeMap<>();

        // fill
        for (OrderStateEnum p : OrderStateEnum.values()) {
            map.put(p.getType(), p.getInfo());
        }
        map.put((short) 0, "所有");

        return map;
    }

}
